/*
 * Copyright (c) 2022, IMMORTA Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * - Neither the name of IMMORTA Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CMP_DRV_H
#define CMP_DRV_H

/*!
 * @file cmp_drv.h
 * @brief This file declares cmp driver interfaces
 */

/*!
 * @addtogroup cmp_drv
 * @{
 */

/*******Includes***************************************************************/
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include "errcodes.h"
#include "clock_drv.h"

/*******Definitions************************************************************/
/*!
 * @brief CMP interrupt status config
 */
typedef struct {
    uint16_t intFlag;             /*!< CMP interrupt falg */
} cmp_int_status_t;

/*!
 * @brief Callback for all peripherals which support CMP features
 */
typedef void (*cmp_callback_t)(uint32_t instance, void* param);

/*!
 * @brief Cmp channel select
 */
typedef enum {
    CMP_EXTERNAL_CH0 = 0U,  /*!< External channel 0 */
    CMP_EXTERNAL_CH1 = 1U,  /*!< External channel 1 */
    CMP_EXTERNAL_CH2 = 2U,  /*!< External channel 2 */
    CMP_EXTERNAL_CH3 = 3U,  /*!< External channel 3 */
    CMP_EXTERNAL_CH4 = 4U,  /*!< External channel 4 */
    CMP_EXTERNAL_CH5 = 5U,  /*!< External channel 5 */
    CMP_EXTERNAL_CH6 = 6U,  /*!< External channel 6 */
    CMP_EXTERNAL_CH7 = 7U,  /*!< External channel 7 */
    CMP_DAC_OUTPUT   = 8U,  /*!< DAC output channel 8 */
    BG_VOLTAGE       = 15U  /*!< BandGap voltage */
} cmp_channel_select_t;

/*!
 * @brief Cmp output result select
 */
typedef enum {
    CMP_OUT_AFTER_FILTER    = 0U,      /*!< CMP output is OUT_FINAL, OUT_FINAL is the output after filter */
    CMP_OUT_BEFORE_WINDOW   = 1U       /*!< CMP output is OUT, OUT is the output before window */
} cmp_output_t;

/*!
 * @brief Cmp hysteresis
 */
typedef enum {
    CMP_HYS_0MV = 0U,        /*!< CMP hysterisis voltage is 0mV */
    CMP_HYS_10MV = 1U,       /*!< CMP hysterisis voltage is 10mV */
    CMP_HYS_20MV = 2U,       /*!< CMP hysterisis voltage is 20mV */
    CMP_HYS_40MV = 3U        /*!< CMP hysterisis voltage is 40mV */
} cmp_hysteresis_t;

/*!
 * @brief Cmp loop mode
 */
typedef enum {
    CMP_NO_LOOP = 0U,        /*!< CMP no port loop */
    CMP_NEG_LOOP = 1U,       /*!< CMP negative port loop */
    CMP_POS_LOOP = 2U,       /*!< CMP positive port loop */
    CMP_NO_LOOP_1 = 3U       /*!< CMP no port loop */
} cmp_loop_mode_t;

/*!
 * @brief Cmp sensitive edge interrupt
 */
typedef enum {
    CMP_FALL_EDGE_INT = 0U,     /*!< CMP output interrupts happen at falling edge */
    CMP_RISE_EDGE_INT = 1U,     /*!< CMP output interrupts happen at rising edge */
    CMP_BOTH_EDGE_INT = 2U      /*!< CMP output interrupts happen at falling or rising edge */
} cmp_sensitive_edge_t;

/*!
 * @brief Cmp dac reference voltage select
 */
typedef enum {
    CMP_DAC_BANDGAP = 0U, /*!< DAC voltage reference is bandgap */
    CMP_DAC_VDD     = 1U  /*!< DAC voltage reference is vdd */
} cmp_dac_volt_reference_t;

/*!
 * @brief Cmp digital filter config
 */
typedef struct {
    bool filterEn;                  /*!< CMP filter enable switch */
    uint8_t filterWidth;            /*!< CMP filter width */
    uint16_t filterClockDiv;        /*!< CMP filter clock divide coff */
} cmp_filter_config_t;

/*!
 * @brief Cmp loop mode config
 */
typedef struct {
    cmp_loop_mode_t loopModeSelect; /*!< CMP loop mode select */
    uint16_t loopFreDiv;            /*!< CMP loop switch frequence divide coff */
    uint16_t loopSequence;          /*!< CMP loop channel sequence */
    bool parallelOutputEn;          /*!< CMP parallel output select enable switch */
    cmp_channel_select_t posA;      /*!< CMP parallel output selectA */
    cmp_channel_select_t posB;      /*!< CMP parallel output selectB */
    cmp_channel_select_t posC;      /*!< CMP parallel output selectC */
    cmp_channel_select_t posD;      /*!< CMP parallel output selectD */
} cmp_loop_mode_config_t;

/*!
 * @brief Cmp comparator config
 */
typedef struct {
    bool windowEn;                                  /*!< CMP window mode enable switch */
    bool cmpOutPinEn;                               /*!< CMP output to pin enable switch */
    bool intEn;                                     /*!< CMP interrupt enable switch */
    bool cmpEn;                                     /*!< CMP module enable switch */
    bool invertEn;                                  /*!< CMP output invert enable switch */
    uint8_t initDelay;                              /*!< CMP channel switch and CMP enable initial delay */
    uint16_t preSetState;                           /*!< CMP loop mode output result pre-set state */
    cmp_clk_src_t srcClk;                           /*!< CMP clock source select */
    cmp_channel_select_t posInput;                  /*!< CMP positive input pin */
    cmp_channel_select_t negInput;                  /*!< CMP negative input pin */
    cmp_output_t outputSelect;                      /*!< CMP output select before or after filter */
    cmp_hysteresis_t hysteresisVolt;                /*!< CMP hysteresis voltage */
    cmp_sensitive_edge_t edgeType;                  /*!< CMP edge type */
    cmp_filter_config_t digFilterConfig;            /*!< CMP filter configure */
    cmp_callback_t callBack;                        /*!< User callback function. Note that this function will be
                                                         called from the interrupt service routine, so its
                                                         execution time should be as small as possible. It can be
                                                         NULL if it is not needed */
    cmp_loop_mode_config_t loopModeConfig;          /*!< CMP loop mode config */
} cmp_comparator_config_t;

/*!
 * @brief Cmp dac config
 */
typedef struct {
    bool dacEn;                             /*!< DAC enable switch */
    bool dacPinEn;                          /*!< DAC output to pin enable switch */
    cmp_clk_src_t srcClk;                   /*!< DAC clock source select */
    cmp_dac_volt_reference_t dacRefVolt;    /*!< DAC reference voltage */
    uint8_t dacValue;                       /*!< DAC output voltage value */
} cmp_dac_config_t;

/*!
 * @brief Cmp comparator and dac config
 */
typedef struct {
    cmp_comparator_config_t comp;         /*!< CMP comparator configure */
    cmp_dac_config_t dac;                 /*!< CMP dac configure */
} cmp_config_t;

/*******APIs*******************************************************************/
#if defined(__cplusplus)
extern "C" {
#endif

/*!
 * @brief Comparator and dac parameters initialize
 *
 * @param[in] instance: Instance number
 * @param[in] cmpConfig: Pointer to the cmp configuration structure
 * @return None
 */
void CMP_Init(uint32_t instance, const cmp_config_t* cmpConfig);

/*!
 * @brief Get comparator and dac initialize configuration
 *
 * @param[in] instance: Instance number
 * @param[out] cmpConfig: Pointer to the cmp configuration structure
 * @return None
 */
void CMP_GetInitConfig(uint32_t instance, cmp_config_t* cmpConfig);

/*!
 * @brief Comparator and dac parameters default value initialize
 *
 * @param[in] instance: Instance number
 * @return None
 */
void CMP_Deinit(uint32_t instance);

/*!
 * @brief Get comparator and dac default configuration with reset value
 *
 * @param[out] cmpConfig: Pointer to the cmp configuration structure
 * @return None
 */
void CMP_GetDefaultConfig(cmp_config_t* cmpConfig);

/*!
 * @brief Comparator parameters initialize
 *
 * @param[in] instance: Instance number
 * @param[in] compConfig: Pointer to the comparator configuration structure
 * @return None
 */
void CMP_ComparatorInit(uint32_t instance, const cmp_comparator_config_t* compConfig);

/*!
 * @brief Get comparator initialize configuration
 *
 * @param[in] instance: Instance number
 * @param[out] cmpConfig: Pointer to the comparator configuration structure
 * @return None
 */
void CMP_GetComparatorInitConfig(uint32_t instance, cmp_comparator_config_t* compConfig);

/*!
 * @brief Get comparator default configuration with reset value
 *
 * @param[out] compConfig: Pointer to the comparator configuration structure
 * @return None
 */
void CMP_GetComparatorDefaultConfig(cmp_comparator_config_t* compConfig);

/*!
 * @brief Dac parameters initialize
 *
 * @param[in] instance: Instance number
 * @param[in] dacConfig: Pointer to the dac configuration structure
 * @return None
 */
void CMP_DacInit(uint32_t instance, const cmp_dac_config_t* dacConfig);

/*!
 * @brief Get dac initialize configuration
 *
 * @param[in] instance: Instance number
 * @param[out] dacConfig: Pointer to the dac configuration structure
 * @return None
 */
void CMP_GetDacInitConfig(uint32_t instance, cmp_dac_config_t* dacConfig);

/*!
 * @brief Get dac default configuration with reset value
 *
 * @param[out] dacConfig: Pointer to the dac configuration structure
 * @return None
 */
void CMP_GetDacDefaultConfig(cmp_dac_config_t* dacConfig);

/*!
 * @brief Set dac value
 *
 * @param[in] instance: Instance number
 * @param[in] value: Dac value, 0-255
 * @return None
 */
void CMP_SetDacValue(uint32_t instance, uint8_t value);

/*!
 * @brief Set comparator positive input channel
 *
 * @param[in] instance: Instance number
 * @param[in] channel: Comparator channel select
 * @return None
 */
void CMP_SetPosPortInput(uint32_t instance, cmp_channel_select_t channel);

/*!
 * @brief Set comparator negative input channel
 *
 * @param[in] instance: Instance number
 * @param[in] channel: Comparator channel select
 * @return None
 */
void CMP_SetNegPortInput(uint32_t instance, cmp_channel_select_t channel);

/*!
 * @brief Get comparator normal mode output result
 *
 * @param[in] instance: Instance number
 * @return Comparator normal mode output result
 */
uint8_t CMP_GetNormalModeOutput(uint32_t instance);

/*!
 * @brief Get comparator loop mode output result
 *
 * @param[in] instance: Instance number
 * @return Comparator loop mode output result
 */
uint16_t CMP_GetLoopModeOutput(uint32_t instance);

/*!
 * @brief Comparator digital filter parameters convert
 *
 * @param[in] instance: Instance number
 * @param[in] filterFerq: Comparator filter frequence
 * @param[in] compConfig: Pointer to the cmp_comparator_config_t structure
 * @return None
 */
void CMP_FilterParamConvert(uint32_t instance, uint32_t filterFerq, cmp_comparator_config_t* compConfig);

/*!
 * @brief Cmp interrupt handler process
 *
 * @param[in] instance: Instance number
 * @return None
 */
void CMP_IRQHandlerProcess(uint32_t instance);

#if defined(__cplusplus)
}
#endif

/*! @} */

#endif /* CMP_DRV_H */

/*******EOF********************************************************************/
